package jp.co.nes.awssupport.test.utility;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import jp.co.nes.awssupport.common.bean.DailyCompiledBillingBean;
import jp.co.nes.awssupport.common.dao.BeanProcessorEx;

/**
 * 日次集計結果アサーションヘルパーです。
 */
public class AssertDailyCompiledBillingHelper extends AbstractAssertHelper<DailyCompiledBillingBean> {

    /** 日次集計結果の件数を検索する際に使用するSelect文 */
    private static final String SEL_COUNT = "select count(*) as Count from daily_compiled_billing";

    /** 日次集計結果を検索する際に使用するSelect文 */
    private static final String SEL = ""
            + "select UUID,"
            + "       LinkedAccountId,"
            + "       YearMonth,"
            + "       ProductName,"
            + "       UsageType,"
            + "       UsageStartDate,"
            + "       UsageEndDate,"
            + "       ResourceId,"
            + "       NameTag,"
            + "       SpotManageFlg,"
            + "       Rate,"
            + "       UsageQuantity,"
            + "       Description,"
            + "       Unit"
            + "  from daily_compiled_billing";

    /**
     * デフォルトコンストラクタです。
     */
    public AssertDailyCompiledBillingHelper() {
        super(DailyCompiledBillingBean.class);
    }

    /**
     * 期待値をソートします。
     */
    public void sortExpected() {
        expectedList.sort(getComparator());
    }

    /**
     * 期待値、結果値をソートして比較します。<br>
     * また、UUIDの比較については除外します。
     */
    @Override
    public void assertTestWithSelect() {
        try {
            Connection connection = JUnitDbConnUtil.getConn();
            QueryRunner runner = new QueryRunner();

            List<Object> paramList = toConditionList(null);
            Object[] params = paramList.toArray();

            List<DailyCompiledBillingBean> actualList = runner.query(connection, getSelectBeanQuery(),
                    new BeanListHandler<>(DailyCompiledBillingBean.class, new BasicRowProcessor(new BeanProcessorEx())),
                    params);
            actualList.sort(getComparator());

            assertThat("actual not exist", actualList, notNullValue());
            assertThat("actual size wrong", actualList.size(), is(expectedList.size()));

            int cnt = 0;
            for (DailyCompiledBillingBean expectedBean : expectedList) {
                AssertUtil.assertBean("(expectedCount=" + cnt + ")", actualList.get(cnt), expectedBean, "getUuid");
                cnt++;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.test.utility.AbstractAssertHelper#getSelectCountQuery()
     */
    @Override
    protected String getSelectCountQuery() {
        return SEL_COUNT;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.test.utility.AbstractAssertHelper#getSelectBeanQuery()
     */
    @Override
    protected String getSelectBeanQuery() {
        return SEL;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.test.utility.AbstractAssertHelper#toConditionList(jp.co.nes.awssupport.common.bean.BaseBean)
     */
    @Override
    protected List<Object> toConditionList(DailyCompiledBillingBean bean) {
        List<Object> conditionList = new ArrayList<>();
        return conditionList;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.test.utility.AbstractAssertHelper#isMatch(jp.co.nes.awssupport.common.bean.BaseBean, jp.co.nes.awssupport.common.bean.BaseBean)
     */
    @Override
    protected boolean isMatch(DailyCompiledBillingBean actualBean, DailyCompiledBillingBean expectedBean) {
        if (actualBean == null) {
            if (expectedBean == null) {
                return true;
            } else {
                return false;
            }
        } else {
            if (expectedBean == null) {
                return false;
            }
        }

        StringBuilder actual = new StringBuilder();
        actual.append(actualBean.getUuid());

        StringBuilder expected = new StringBuilder();
        expected.append(expectedBean.getUuid());

        if (actual.toString().equals(expected.toString())) {
            return true;
        }
        return false;
    }

    /**
     * 期待値、結果値をソートするためのコンパレータを返却します。
     *
     * @return Comparator コンパレータ
     */
    private Comparator<DailyCompiledBillingBean> getComparator() {
        Comparator<DailyCompiledBillingBean> c1 = Comparator.comparing(bean -> bean.getLinkedAccountId());
        Comparator<DailyCompiledBillingBean> c2 = Comparator.comparing(bean -> bean.getYearMonth());
        Comparator<DailyCompiledBillingBean> c3 = Comparator.comparing(bean -> bean.getProductName());
        Comparator<DailyCompiledBillingBean> c4 = Comparator.comparing(bean -> bean.getUsageType());
        Comparator<DailyCompiledBillingBean> c5 = Comparator.comparing(bean -> bean.getUsageStartDate());
        Comparator<DailyCompiledBillingBean> c6 = Comparator.comparing(bean -> bean.getUsageEndDate());
        Comparator<DailyCompiledBillingBean> c7 = Comparator.comparing(bean -> {
            String sortKey = bean.getResourceId();
            if (sortKey == null) {
                sortKey = "null";
            }
            return sortKey;
        });
        Comparator<DailyCompiledBillingBean> c8 = Comparator.comparing(bean -> bean.getRate());
        Comparator<DailyCompiledBillingBean> c = c1.thenComparing(c2).thenComparing(c3).thenComparing(c4)
                .thenComparing(c5).thenComparing(c6).thenComparing(c7).thenComparing(c8);
        return c;
    }
}
